package guiservice.client;

import guiservice.common.controls.*;
import guiservice.common.controls.handlers.KeyEventArgs;
import guiservice.common.controls.handlers.MouseEventArgs;
import guiservice.common.controls.handlers.MouseEventType;
import guiservice.common.net.Server;
import lombok.extern.log4j.Log4j;

import java.io.IOException;
import java.util.List;

@Log4j
public class Application {

    private final ClientImpl client;

    protected Application() {
        client = new ClientImpl(this);
    }

    public void run() throws IOException, InterruptedException {
        client.start();
        while (client.getUid() == -1) {
            Thread.sleep(100);
        }
    }

    public void close() {
        client.stop();
    }

    protected Window createWindow() {
        Window window = client.createAndGetRemoteObject(client.getUid(), Window.class.getSimpleName(), Window.class);
        Button closeButton = client.createAndGetRemoteObject(window.getId(), Button.class.getSimpleName(), Button.class);
        window.initializeCloseButton(closeButton.getId());
        addMouseEventListener(closeButton, new MouseEventHandler<Button>() {
            @Override
            public void handler(Button control, MouseEventArgs args) {
                close();
            }
        });
        return window;
    }

    protected Button createButton(Control owner) {
        return client.createAndGetRemoteObject(owner.getId(), Button.class.getSimpleName(), Button.class);
    }

    protected Label createLabel(Control owner) {
        return client.createAndGetRemoteObject(owner.getId(), Label.class.getSimpleName(), Label.class);
    }

    protected TextBox createTextBox(Control owner) {
        return client.createAndGetRemoteObject(owner.getId(), TextBox.class.getSimpleName(), TextBox.class);
    }

    protected TextArea createTextArea(Control owner) {
        TextArea ta = client.createAndGetRemoteObject(owner.getId(), TextArea.class.getSimpleName(), TextArea.class);
        addMouseEventListener(ta, new MouseEventHandler<TextArea>() {
            @Override
            public void handler(TextArea control, MouseEventArgs args) {
                if (args.getType() == MouseEventType.Scroll) {
                    control.moveScroll(args.getScrollAmount());
                    client.getServerImpl().invalidate();
                }
            }
        });
        return ta;
    }

    protected <T extends Control> void addMouseEventListener(T control, MouseEventHandler<T> handler) {
        EventHandler.getInstance().addMouseEventListener(control, handler);
    }

    protected <T extends Control> void addKeyEventListener(T control, KeyEventHandler<T> handler) {
        EventHandler.getInstance().addKeyEventListener(control, handler);
    }

    protected void invalidate() {
        Server serverImpl = client.getServerImpl();
        if (serverImpl != null)
            serverImpl.invalidate();
    }

    protected <T extends Control> T getControl(long id, Class<T> clazz) {
        return client.getControl(id, clazz, true);
    }

    protected Long[] getClients() {
        return client.getServerImpl().getClients();
    }

    protected List<Window> getWindows(long uid) {
        return client.getControls(uid, Window.class);
    }

    protected List<TextArea> getTextAreas(long uid) {
        return client.getControls(uid, TextArea.class);
    }

    protected List<Button> getButtons(long uid) {
        return client.getControls(uid, Button.class);
    }

    protected List<TextBox> getTextBoxes(long uid) {
        return client.getControls(uid, TextBox.class);
    }

    protected List<Label> getLabels(long uid) {
        return client.getControls(uid, Label.class);
    }

    protected void eventHandler(long objectId, long uid, MouseEventArgs args) {
        Server serverImpl = client.getServerImpl();
        if (serverImpl != null) {
            serverImpl.eventHandler(objectId, uid, args);
        }
    }

    protected void eventHandler(long objectId, long uid, KeyEventArgs args) {
        Server serverImpl = client.getServerImpl();
        if (serverImpl != null) {
            serverImpl.eventHandler(objectId, uid, args);
        }
    }

    protected long getId() {
        return client.getUid();
    }
}
